package com.zxl.app.service;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.github.pagehelper.PageHelper;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import com.zxl.app.context.UserContext;
import com.zxl.common.constant.order.OrderStatusConstant;
import com.zxl.common.exception.BusinessException;
import com.zxl.common.mapper.*;
import com.zxl.common.model.WxV3payConfig;
import com.zxl.common.model.bo.order.CreateOrderBo;
import com.zxl.common.model.pojo.*;
import com.zxl.common.model.query.order.MyOrderListQuery;
import com.zxl.common.model.query.order.PayQuery;
import com.zxl.common.model.vo.goods.GoodsCartVo;
import com.zxl.common.model.vo.order.OrderDetailsVo;
import com.zxl.common.model.vo.order.OrderGoodsDetailVo;
import com.zxl.common.model.vo.order.OrderList;
import com.zxl.common.service.SysOrderService;
import com.zxl.common.utils.OrderUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author zxw
 * @date 2023/4/1
 */
@Service
@Slf4j
public class OrderService {
    @Resource
    private SysOrderMapper sysOrderMapper;
    @Resource
    private SysOrderGoodsMapper sysOrderGoodsMapper;
    @Resource
    private SysMemberAddressMapper sysMemberAddressMapper;
    @Resource
    private SysMemberMapper sysMemberMapper;
    @Resource
    private SysGoodsMapper sysGoodsMapper;
    @Resource
    private SysOrderAddressMapper sysOrderAddressMapper;
    @Resource
    private SysShoppingCartMapper sysShoppingCartMapper;
    @Resource
    private SysOrderService sysOrderService;
    @Resource
    private WxV3payConfig wxV3payConfig;
    @Value("${spring.profiles.active}")
    private String env;


    public List<OrderList> list(MyOrderListQuery query) {
        if (query.getOrderStatus() != null) {
            if (query.getOrderStatus().equals("0")) {
                query.setOrderStatus(null);
            }
        }
        PageHelper.startPage(query.getPageNumber(), query.getPageSize());
        List<OrderList> orderLists = sysOrderMapper.list(query.getMemberId(), query.getOrderStatus());
        for (OrderList orderList : orderLists) {
            List<OrderGoodsDetailVo> list = sysOrderGoodsMapper.list(orderList.getOrderCode());
            orderList.setOrderGoodsDetailVos(list);
        }
        return orderLists;

    }


    public OrderDetailsVo getOrderDetails(String orderCode) {
        OrderDetailsVo orderDetails = sysOrderMapper.getOrderDetails(orderCode);
        List<OrderGoodsDetailVo> list = sysOrderGoodsMapper.list(orderCode);
        orderDetails.setOrderGoodsDetailVo(list);
        return orderDetails;
    }

    @Transactional(rollbackFor = Exception.class)
    public String createOrder(CreateOrderBo createOrderBo) {
        /**  生成订单  **/
        SysOrder sysOrder = new SysOrder();
        sysOrder.setOrderCode(OrderUtils.generatorOrderCode(OrderUtils.C_PREFIX));
        sysOrder.setOrderStatus(OrderStatusConstant.ORDER_STATUS_WAITPAY.getCode());
        sysOrder.setOrderPrice(createOrderBo.getOrderPrice());
        sysOrder.setPayPrice(createOrderBo.getOrderPrice());
        sysOrder.setMemberId(createOrderBo.getMemberId());
        sysOrderMapper.insert(sysOrder);
        /**  生成订单地址  **/
        SysMemberAddress address = sysMemberAddressMapper.selectOne(new QueryWrapper<SysMemberAddress>()
                .eq("id", createOrderBo.getAddressId()));
        SysOrderAddress sysOrderAddress = new SysOrderAddress();
        sysOrderAddress.setOrderCode(sysOrder.getOrderCode());
        sysOrderAddress.setReceiverName(address.getReceiverName());
        sysOrderAddress.setReceiverTel(address.getReceiverTel());
        sysOrderAddress.setReceiverDetail(address.getReceiverDetail());
        sysOrderAddressMapper.insert(sysOrderAddress);
        /**  生成订单商品  **/
        List<GoodsCartVo> goodsCartVoList = createOrderBo.getGoodsCart();
        for (GoodsCartVo goodsCartVo : goodsCartVoList) {
            SysOrderGoods sysOrderGoods = new SysOrderGoods();
            sysOrderGoods.setOrderCode(sysOrder.getOrderCode());
            BeanUtil.copyProperties(goodsCartVo, sysOrderGoods);
            sysOrderGoodsMapper.insert(sysOrderGoods);
            /**  修改商品信息  **/
            SysGoods sysGoods = sysGoodsMapper.selectOne(new QueryWrapper<SysGoods>()
                    .eq("goods_code", goodsCartVo.getGoodsCode()));
            if (sysGoods.getGoodsStock() < goodsCartVo.getGoodsNum()) {
                throw new BusinessException(goodsCartVo.getGoodsName() + "商品库存不足");
            }
            sysGoodsMapper.updateStockSales(goodsCartVo.getGoodsCode(), goodsCartVo.getGoodsNum());
        }
        List<String> goodsCodes = goodsCartVoList.stream().map(v -> v.getGoodsCode()).collect(Collectors.toList());
        sysShoppingCartMapper.deleteByGoodsCode(createOrderBo.getMemberId(), goodsCodes);
        return sysOrder.getOrderCode();
    }

    public void complete(String orderCode, Integer memberId) {
        SysOrder sysOrder = sysOrderMapper.selectOne(new QueryWrapper<SysOrder>()
                .eq("order_code", orderCode)
                .eq("member_id", memberId));
        if (sysOrder == null) {
            throw new BusinessException("订单不存在");
        }
        sysOrderMapper.update(null, new UpdateWrapper<SysOrder>()
                .eq("order_code", orderCode)
                .set("order_status", OrderStatusConstant.ORDER_STATUS_COMPLETE.getCode()));

    }

    @Transactional(rollbackFor = Exception.class)
    public void cancel(String orderCode, Integer memberId) {
        SysOrder sysOrder = sysOrderMapper.selectOne(new QueryWrapper<SysOrder>()
                .eq("order_code", orderCode)
                .eq("member_id", memberId));
        if (sysOrder == null) {
            throw new BusinessException("订单不存在");
        }
        if (!OrderStatusConstant.ORDER_STATUS_WAITPAY.getCode().equals(sysOrder.getOrderStatus())) {
            throw new BusinessException("待付款订单才能取消");
        }
        SysOrder order = new SysOrder();
        order.setId(sysOrder.getId());
        order.setOrderStatus(OrderStatusConstant.ORDER_STATUS_CANCEL.getCode());
        sysOrderMapper.updateById(order);

        /**  修改商品信息  **/
        List<OrderGoodsDetailVo> orderGoodsDetailVoList = sysOrderGoodsMapper.list(orderCode);
        for (OrderGoodsDetailVo orderGoodsDetailVo : orderGoodsDetailVoList) {
            sysGoodsMapper.cancelStockSales(orderGoodsDetailVo.getGoodsCode(), orderGoodsDetailVo.getGoodsNum());
        }
    }


    public JSONObject pay(PayQuery query) throws Exception {
        log.info("支付进入请求");
        //判断自己的业务逻辑
        SysMember sysMember = sysMemberMapper.selectById(UserContext.getUserId());
        SysOrder sysOrder = sysOrderMapper.selectOne(new QueryWrapper<SysOrder>()
                .eq("order_code", query.getOrderCode()));
        this.validFrontPay(sysMember, sysOrder);
        String openId = sysMember.getOpenId();

        //开始支付,创建数据体
        JSONObject order = new JSONObject();
        order.put("appid", wxV3payConfig.getAppletAppid());
        order.put("mchid", wxV3payConfig.getAppletMchid());
        order.put("description", "支付");
        order.put("out_trade_no", sysOrder.getOrderCode());
        order.put("notify_url", "https://j.kaletcg.com/lzmtest/app/order/pay_notice");
        JSONObject amount = new JSONObject();
        Integer orderAmt = sysOrder.getPayPrice().multiply(new BigDecimal("100")).intValue();
        amount.put("total", orderAmt);
        amount.put("currency", "CNY");
        order.put("amount", amount);
        JSONObject payer = new JSONObject();
        payer.put("openid", openId);
        order.put("payer", payer);
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(Objects.requireNonNull(getClass().getResourceAsStream("/appletPrivateKey.pem")));
        AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                new WechatPay2Credentials(wxV3payConfig.getAppletMchid(), new PrivateKeySigner(wxV3payConfig.getAppletMchSerialNo(), merchantPrivateKey)),
                wxV3payConfig.getAppletApiV3Key().getBytes(StandardCharsets.UTF_8));


        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                .withMerchant(wxV3payConfig.getAppletMchid(), wxV3payConfig.getAppletMchSerialNo(), merchantPrivateKey)
                .withValidator(new WechatPay2Validator(verifier));
        HttpClient httpClient = builder.build();
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");
        httpPost.addHeader("Accept", "application/json");
        httpPost.addHeader("Content-type", "application/json;charset=utf-8");
        httpPost.setEntity(new StringEntity(order.toJSONString(), "UTF-8"));
        HttpResponse response = httpClient.execute(httpPost);
        String body = EntityUtils.toString(response.getEntity());
        JSONObject jsonObject = JSONObject.parseObject(body);
        if (jsonObject.containsKey("code")) {
            log.error(jsonObject.getString("message"));
            return new JSONObject();
        }

        String prepayId = jsonObject.getString("prepay_id");
        String timeStamp = System.currentTimeMillis() + "";
        String nonceStr = sysOrder.getOrderCode();

        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(wxV3payConfig.getAppletAppid() + "\n");
        stringBuffer.append(timeStamp + "\n");
        stringBuffer.append(nonceStr + "\n");
        stringBuffer.append("prepay_id=" + prepayId + "\n");

        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(merchantPrivateKey);
        signature.update(stringBuffer.toString().getBytes(StandardCharsets.UTF_8));
        String paySign = Base64.getEncoder().encodeToString(signature.sign());

        JSONObject params = new JSONObject();
        params.put("appId", wxV3payConfig.getAppletAppid());
        params.put("timeStamp", timeStamp);
        params.put("nonceStr", nonceStr);
        params.put("package", "prepay_id=" + prepayId);
        params.put("signType", "RSA");
        params.put("paySign", paySign);
        log.info("支付返回前端信息：" + params);
        return params;
    }

    public void validFrontPay(SysMember sysMember, SysOrder sysOrder){
        if (sysMember == null) {
            throw new BusinessException("没有找到该会员信息");
        }
        if (sysOrder == null){
            throw new BusinessException("订单不存在");
        }

        if (!OrderStatusConstant.ORDER_STATUS_WAITPAY.getCode().equals(sysOrder.getOrderStatus())) {
            throw new BusinessException("待付款订单才能支付");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void payNotice(JSONObject json) throws Exception {
        String ciphertext = json.getJSONObject("resource").getString("ciphertext");
        final String associated_data = json.getJSONObject("resource").getString("associated_data");
        final String nonce = json.getJSONObject("resource").getString("nonce");
        AesUtil aesUtil = new AesUtil(wxV3payConfig.getAppletApiV3Key().getBytes(StandardCharsets.UTF_8));
        ciphertext = aesUtil.decryptToString(associated_data.getBytes(), nonce.getBytes(), ciphertext);
        JSONObject jsonObject = JSONObject.parseObject(ciphertext);
        log.info("回调信息" + jsonObject);
        //商户单号（订单号）
        String out_trade_no = JSONObject.parseObject(ciphertext).getString("out_trade_no");
        //交易单号
        String transaction_id = JSONObject.parseObject(ciphertext).getString("transaction_id");

        this.handleOrderByPay(out_trade_no, transaction_id);
    }

    public void handleOrderByPay(String out_trade_no, String transaction_id) {
        SysOrder sysOrder = sysOrderMapper.selectOne(new QueryWrapper<SysOrder>()
                .eq("order_code", out_trade_no));
        if (sysOrder == null){
            throw new BusinessException("微信支付回调，订单不存在");
        }
        /*  计算手续费  */
        sysOrderService.countReceivedAmount(sysOrder);
        sysOrder.setOrderStatus(OrderStatusConstant.ORDER_STATUS_WAITSEND.getCode());
        sysOrder.setPayTime(new Date());
        sysOrder.setTransactionId(transaction_id);
        sysOrder.setPayMode(1);
        sysOrderMapper.updateById(sysOrder);
    }
}